package com.billlv.codegenerator.controller;

import com.billlv.codegenerator.common.config.CookieProperties;
import com.billlv.codegenerator.common.utils.JwtUtils;
import com.billlv.codegenerator.common.utils.Result;
import com.billlv.codegenerator.domain.dto.LoginRequestDTO;
import com.billlv.codegenerator.domain.vo.UsersVO;
import com.billlv.codegenerator.exception.global.ErrorCode;
import com.billlv.codegenerator.exception.user.UserException;
import com.billlv.codegenerator.service.AuthService;
import com.billlv.codegenerator.service.BlacklistService;
import com.billlv.codegenerator.service.TokenService;
import com.billlv.codegenerator.service.UserContextService;
import com.billlv.codegenerator.service.impl.UserDetailsImpl;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;

import java.util.*;

@Slf4j
@RestController
@RequestMapping("/api/auth")
public class AuthController {

    @Autowired
    private AuthService authService;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private CookieProperties cookieProperties;

    @Autowired
    private UserContextService userContextService;

    @Autowired
    private TokenService tokenService;


    @Autowired
    private BlacklistService blacklistService;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequestDTO loginRequest, HttpServletResponse response) {
        // 调用 AuthService 的登录逻辑
        Authentication authentication = null;
        try {
            authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            loginRequest.getUsername(),
                            loginRequest.getPassword()
                    )
            );
        } catch (AuthenticationException e) {
            if(e instanceof  org.springframework.security.authentication.BadCredentialsException){
                throw new UserException(ErrorCode.USER_NOT_FOUND);

            }
        }
        Long userId = ((UserDetailsImpl) authentication.getPrincipal()).getUserId();
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        List<String> roleList= new ArrayList<>();
        for (GrantedAuthority authority : authorities) {
            roleList.add(authority.getAuthority());
        }
        SecurityContextHolder.getContext().setAuthentication(authentication);
        String accessToken = jwtUtils.generateAccessToken(userId+"");
        String refreshToken = jwtUtils.generateRefreshToken(userId+"");
        tokenService.saveToken(userId,refreshToken);
        // 设置 Refresh Token 到 Cookie
        Cookie refreshTokenCookie = new Cookie(cookieProperties.getRefreshToken().getName(),refreshToken);
        refreshTokenCookie.setHttpOnly(cookieProperties.getRefreshToken().isHttpOnly());
        refreshTokenCookie.setPath(cookieProperties.getRefreshToken().getPath());
        refreshTokenCookie.setMaxAge(cookieProperties.getRefreshToken().getMaxAge());
        response.addCookie(refreshTokenCookie);
        userContextService.getCurrentUser();
        Map<String, Object> responseBody = new HashMap<>();
        responseBody.put("success", true);
        responseBody.put("accessToken", accessToken);
        responseBody.put("roleList", roleList);
        return ResponseEntity.ok(responseBody);
    }

    @PostMapping("/refresh-token")
    public ResponseEntity<?> browserRefreshAccessToken(HttpServletRequest request, HttpServletResponse response) {
        // 1. 从请求头获取 Token（兼容微信小程序）
        String refreshToken = extractRefreshTokenFromCookie(request);
        if (refreshToken == null || !jwtUtils.validateJwtToken(refreshToken)) {
            return ResponseEntity.status(HttpServletResponse.SC_UNAUTHORIZED).body(Result.failure(500,"Old password is incorrect"));
        }
        String oldTokenId = jwtUtils.getTokenId(refreshToken);
        if(blacklistService.isBlacklisted(oldTokenId)){
            return ResponseEntity.status(HttpServletResponse.SC_UNAUTHORIZED).body(Result.failure(500,"Old password is incorrect"));
        }
        Map<String, Object> responseBody = new HashMap<>();
        // 检查 Token 的过期时间
        long expirationTime = jwtUtils.getExpirationTime(refreshToken).getTime();
        long currentTime = System.currentTimeMillis();
        String userId = jwtUtils.getUserIdFromToken(refreshToken);
        String newAccessToken = jwtUtils.generateAccessToken(userId);
        String newRefreshToken = jwtUtils.generateRefreshToken(userId);
        tokenService.saveToken(Long.parseLong(userId),newRefreshToken);
        // 将旧的 Refresh Token 加入黑名单
        long remainingTtl = (expirationTime - currentTime) / 1000; // 秒
        blacklistService.addToBlacklist(oldTokenId, remainingTtl);
        // 设置 Refresh Token 到 Cookie
        Cookie newrefreshTokenCookie = new Cookie(cookieProperties.getRefreshToken().getName(),newRefreshToken);
        newrefreshTokenCookie.setHttpOnly(cookieProperties.getRefreshToken().isHttpOnly());
        newrefreshTokenCookie.setPath(cookieProperties.getRefreshToken().getPath());
        newrefreshTokenCookie.setMaxAge(cookieProperties.getRefreshToken().getMaxAge());
        response.addCookie(newrefreshTokenCookie);
        responseBody.put("success", true);
        responseBody.put("accessToken", newAccessToken);
        return ResponseEntity.ok(responseBody);
    }


    @PostMapping("/logout")
    public ResponseEntity<?> logout(HttpServletRequest request, HttpServletResponse response) {
        // 验证并提取 Token ID
        // 2. 如果请求头没有 Token，从 Cookie 获取 Token（浏览器兼容）
        String refreshToken = extractRefreshTokenFromCookie(request);
        if (refreshToken == null || !jwtUtils.validateJwtToken(refreshToken)) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Result.failure(500,"Old password is incorrect"));
        }
        String tokenId = jwtUtils.getTokenId(refreshToken);
        long expirationTime = jwtUtils.getExpirationTime(refreshToken).getTime();
        long currentTime = System.currentTimeMillis();
        // 将旧的 Refresh Token 加入黑名单
        long remainingTtl = (expirationTime - currentTime) / 1000; // 秒
        blacklistService.addToBlacklist(tokenId, remainingTtl);
        // 清除客户端的 Token
        clearTokenCookies(response);
        Map<String, Object> responseBody = new HashMap<>();
        responseBody.put("success", true);
        return ResponseEntity.ok(responseBody);
    }


    @GetMapping("/me")
    public ResponseEntity<Result<UsersVO>> getAllMenus() {
        UsersVO currentUser = userContextService.getCurrentUser();
        currentUser.setPassword(null);
        return ResponseEntity.ok(Result.success(currentUser));
    }



    private void clearTokenCookies(HttpServletResponse response) {
        // 清除 Refresh Token Cookie
        Cookie refreshTokenCookie = new Cookie("refreshToken", null);
        refreshTokenCookie.setHttpOnly(true);
        refreshTokenCookie.setSecure(true); // 如果使用 HTTPS，请设置为 true
        refreshTokenCookie.setPath("/");
        refreshTokenCookie.setMaxAge(0); // 设置为 0 表示立即删除
        response.addCookie(refreshTokenCookie);
    }



    /**
     * 从 Cookie 中提取 Refresh Token
     */
    private String extractRefreshTokenFromCookie(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookieProperties.getRefreshToken().getName().equals(cookie.getName())) { // 假设 Cookie 名为 'refreshToken'
                    return cookie.getValue();
                }
            }
        }
        return null;
    }

}
